package com.xpec.net.xnetty.h5cihper;

import java.net.SocketAddress;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.DownstreamMessageEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.UpstreamMessageEvent;

import com.xpec.cipher.CipherHandler;

/**
 * XNetty 的 CipherHandler 一個負責處理 Cipher過程訊息收送的 Handler 包含讀數據, 送消息, pass消息給下個
 * ChannelHandler, 通知工作完成等
 */
public class H5XNettyCipherHandler implements CipherHandler
{
	private static final Log logger = LogFactory.getLog(H5XNettyCipherHandler.class);
	
	ChannelHandlerContext ctx;

	MessageEvent msgEvent;

	ChannelBuffer realContent;

	H5BaseCipherChannelHandler cipherChannelHandler;

	public H5XNettyCipherHandler(ChannelHandlerContext ctx, MessageEvent msgEvent,
								ChannelBuffer realContent,
								H5BaseCipherChannelHandler cihperChannelHandler)
	{
		this.ctx = ctx;
		this.msgEvent = msgEvent;
		this.realContent = realContent;
		this.cipherChannelHandler = cihperChannelHandler;
	}

	public H5XNettyCipherHandler(ChannelHandlerContext ctx, MessageEvent msgEvent,
								H5BaseCipherChannelHandler cihperChannelHandler)
	{
		this.ctx = ctx;
		this.msgEvent = msgEvent;
		this.realContent = null;
		this.cipherChannelHandler = cihperChannelHandler;
	}

	/**
	 * 動態改變 pipeline中的 ChannelHandler
	 */
	public void addOtherChannelHandler()
	{
		this.cipherChannelHandler.addOtherHandler(this.ctx.getChannel());
	}

	/**
	 * 通知外部 Cipher 握手已經成功
	 */
	@Override
	public void notifyCipherFinished()
	{
		this.cipherChannelHandler.notifyCipherFinish(this.ctx.getChannel());
	}

	@Override
	public ChannelBuffer getPacketContent()
	{
		ChannelBuffer buffer = (ChannelBuffer) this.msgEvent.getMessage();
		return buffer;
	}

	@Override
	public Object getParameter(Integer key)
	{
		return cipherChannelHandler.getParameter(key);
	}

	@Override
	public void setParameter(Integer key, Object value)
	{
		cipherChannelHandler.saveParameter(key, value);
	}

	@Override
	public int getRealContentRemain()
	{
		return realContent.readableBytes();
	}

	@Override
	public void passMessage(int passAction)
	{
		if (passAction == PASS_MESSAGE_RECEIVE)
		{
			this.ctx.sendUpstream(this.msgEvent);
		}
		else
		{
			this.ctx.sendDownstream(this.msgEvent);
		}
	}

	@Override
	public void passMessage(ChannelBuffer data, SocketAddress socketAddress, int passAction)
	{
		throw new UnsupportedOperationException();
	}

	@Override
	public void passMessage(ChannelBuffer data, int passAction)
	{			
		if(passAction == CipherHandler.PASS_MESSAGE_RECEIVE)
		{
			UpstreamMessageEvent event = new UpstreamMessageEvent(this.msgEvent.getChannel(),
					data, this.msgEvent.getRemoteAddress());
			this.msgEvent = event;
			
			this.ctx.sendUpstream(this.msgEvent);
		}
		else
		{
			DownstreamMessageEvent oriMsgEvent = (DownstreamMessageEvent) this.msgEvent;
			DownstreamMessageEvent event = new DownstreamMessageEvent(
						oriMsgEvent.getChannel(),oriMsgEvent.getFuture(),
							data,oriMsgEvent.getRemoteAddress());
			this.msgEvent = event;
			
			this.ctx.sendDownstream(this.msgEvent);
		}
	}

	@Override
	public void readByteFromRealContent(byte[] data)
	{
		this.realContent.readBytes(data);
	}

	@Override
	public int readUnsignedByteFromRealContent()
	{
		return this.realContent.readUnsignedByte();
	}

	@Override
	public void sendData(ChannelBuffer data, SocketAddress socketAddress, boolean isFutureConcern)
	{
		Channel channel = this.msgEvent.getChannel();
		ChannelFuture future = channel.write(data, socketAddress);
		
		if (isFutureConcern)
		{
			future.addListener(this.cipherChannelHandler);
		}
	}

	@Override
	public void sendData(ChannelBuffer data, boolean isFutureConcern)
	{
		Channel channel = this.msgEvent.getChannel();
		ChannelFuture future = channel.write(data);
		
		if (isFutureConcern)
		{
			future.addListener(this.cipherChannelHandler);
		}
	}

}
